package com.github.ilioili.justdoit.widget;

import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.DecelerateInterpolator;

import com.github.ilioili.justdoit.R;

/**
 * Created by hantuo on 16/5/17.
 */
public class WatchTimePicker extends View {
    private int hour = 0;
    private int minute = 0;
    private Paint textPaint;
    private Paint paint;
    private int cx;
    private int cy;
    private int radius;
    private int watchBgColor;
    private int hourIndicatorColor;
    private int minuteIndicatorColor;
    private boolean dragMinuteIndicator;
    private String[] hourStr = new String[]{"Ⅰ", "Ⅱ", "Ⅲ", "Ⅳ", "Ⅴ", "Ⅵ", "Ⅶ", "Ⅷ", "Ⅸ", "Ⅹ", "Ⅺ", "Ⅻ"};
//    private String[] hourStr = new String[]{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"};

    public void setTime(final int hour, final int minute, final boolean animate) {
        post(new Runnable() {
            @Override
            public void run() {
                WatchTimePicker.this.hour = hour;
                if (WatchTimePicker.this.hour >= 12) {
                    WatchTimePicker.this.hour -= 12;
                }
                WatchTimePicker.this.minute = minute;
                int curMinutes = WatchTimePicker.this.hour*60+WatchTimePicker.this.minute;
                int startMinute = curMinutes-120;
                if (animate) {
                        ValueAnimator valueAnimator = ValueAnimator.ofInt(startMinute, curMinutes);
                        valueAnimator.setDuration(getResources().getInteger(android.R.integer.config_longAnimTime));
                        valueAnimator.setInterpolator(new DecelerateInterpolator());
                        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                            @Override
                            public void onAnimationUpdate(ValueAnimator animation) {
                                int value = (int) animation.getAnimatedValue();
                                int h = value/60;
                                int m = value%60;
                                WatchTimePicker.this.hour = h;
                                WatchTimePicker.this.minute = m;
                                postInvalidate();
                            }
                        });
                    valueAnimator.start();
                } else {
                    postInvalidate();
                }
            }
        });
    }

    private void modifyHour() {
        while (hour > 11) {
            hour -= 12;
        }
        while (hour < 0) {
            hour += 12;
        }
    }

    private void modifyMinute() {
        while (minute > 59) {
            minute -= 60;
        }
        while (minute < 0) {
            minute += 60;
        }
    }


    private void init(Context context, AttributeSet attrs, int defStyleAttr) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.WatchTimePicker, defStyleAttr, 0);
        textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        textPaint.setFakeBoldText(true);
        textPaint.setColor(Color.BLACK);
        textPaint.setTextSize(typedArray.getDimension(R.styleable.WatchTimePicker_hour_text_size, 50));
        textPaint.setColor(typedArray.getColor(R.styleable.WatchTimePicker_hour_text_color, Color.BLACK));
        textPaint.setTextAlign(Paint.Align.CENTER);
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setStyle(Paint.Style.FILL_AND_STROKE);
        paint.setStrokeCap(Paint.Cap.ROUND);
        watchBgColor = typedArray.getColor(R.styleable.WatchTimePicker_watch_background_color, Color.GRAY);
        hourIndicatorColor = typedArray.getColor(R.styleable.WatchTimePicker_hour_indicator_color, Color.BLACK);
        minuteIndicatorColor = typedArray.getColor(R.styleable.WatchTimePicker_minute_indicator_color, Color.BLACK);
        typedArray.recycle();
    }

    public WatchTimePicker(Context context) {
        this(context, null);
    }

    public WatchTimePicker(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public WatchTimePicker(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs, defStyleAttr);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public WatchTimePicker(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context, attrs, defStyleAttr);
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float dx = event.getX() - cx;
        float dy = cy - event.getY();
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            if( dx * dx + dy * dy > radius * radius) return false;
            dragMinuteIndicator = dx * dx + dy * dy > radius * radius * 0.6 * 0.6;
        }

        double r = Math.sqrt(dx * dx + dy * dy);
        double angle = Math.asin(dy / r);
        if (dx > 0) {
            angle = Math.PI / 2 - angle;
        } else if (dx < 0) {
            angle = angle + Math.PI * 3 / 2;
        }

        if (dragMinuteIndicator) {
            int m = (int) (angle * 30 / Math.PI);
            if (m != minute) {
                if (m < 10 && minute > 50) {
                    hour++;
                    if (hour == 12) {
                        hour = 0;
                    }
                } else if (m > 50 && minute < 10) {
                    hour--;
                    if (hour == -1) {
                        hour = 11;
                    }
                }
                minute = m;
                invalidate();
                if (null != timeSelectListener) timeSelectListener.onTimeSelected(hour, minute);
            }
        } else {
            int h = (int) (angle * 6 / Math.PI);
            if (h != hour) {
                hour = h;
                postInvalidate();
                if (null != timeSelectListener) timeSelectListener.onTimeSelected(hour, minute);
            }
        }
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        paint.setColor(watchBgColor);
        canvas.drawCircle(cx, cy, radius, paint);

        float textHeight = -textPaint.descent() + (-textPaint.ascent() + textPaint.descent()) / 2;
        for (int i = 0; i < 12; i++) {
            double angle = i * Math.PI / 6 - Math.PI / 2;
            canvas.drawText(hourStr[i], 0, hourStr[i].length(), (float) (cx + 0.8f * radius * Math.cos(angle)), (float) (cy + textHeight + 0.8f * radius * Math.sin(angle)), textPaint);
        }


        double minuteAngle = minute * Math.PI / 30 - Math.PI / 2;
        paint.setColor(minuteIndicatorColor);
        paint.setStrokeWidth(5);
        canvas.drawLine((float) (cx - 0.1f * radius * Math.cos(minuteAngle)), (float) (cy - 0.1f * radius * Math.sin(minuteAngle)), (float) (cx + 0.7f * radius * Math.cos(minuteAngle)), (float) (cy + 0.7f * radius * Math.sin(minuteAngle)), paint);

        double hourAngle = hour * Math.PI / 6 - Math.PI / 2 + minute * Math.PI / 30 / 12;
        paint.setStrokeWidth(10);
        paint.setColor(hourIndicatorColor);
        canvas.drawLine((float) (cx - 0.1f * radius * Math.cos(hourAngle)), (float) (cy - 0.1f * radius * Math.sin(hourAngle)), (float) (cx + 0.5f * radius * Math.cos(hourAngle)), (float) (cy + 0.5f * radius * Math.sin(hourAngle)), paint);

        canvas.drawCircle(cx, cy, 15, paint);
    }

    public void setOnTimeSelectListener(OnTimeSelectListener onTimeSelectListener) {
        timeSelectListener = onTimeSelectListener;
    }

    public interface OnTimeSelectListener {
        void onTimeSelected(int hour, int minute);
    }

    private OnTimeSelectListener timeSelectListener;

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        cx = w / 2;
        cy = h / 2;
        int realW = w - getPaddingLeft() - getPaddingRight();
        int realH = h - getPaddingTop() - getPaddingBottom();
        radius = (realH < realW ? realH : realW) / 2 - 1;
    }
}
